import os
import uuid
import hashlib
import mimetypes
from datetime import datetime
from typing import Dict, Any, List, Optional
from django.conf import settings
from django.core.files.storage import default_storage
from django.utils.text import slugify

def generate_unique_filename(original_filename: str, prefix: str = '') -> str:
    """生成唯一的文件名"""
    # 获取文件扩展名
    name, ext = os.path.splitext(original_filename)
    
    # 生成唯一标识符
    unique_id = str(uuid.uuid4())[:8]
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    
    # 清理文件名
    clean_name = slugify(name)[:50]  # 限制长度
    
    # 组合文件名
    if prefix:
        filename = f"{prefix}_{clean_name}_{timestamp}_{unique_id}{ext}"
    else:
        filename = f"{clean_name}_{timestamp}_{unique_id}{ext}"
    
    return filename

def calculate_file_hash(file_path: str, algorithm: str = 'md5') -> str:
    """计算文件哈希值"""
    hash_func = hashlib.new(algorithm)
    
    with open(file_path, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_func.update(chunk)
    
    return hash_func.hexdigest()

def get_file_info(file_path: str) -> Dict[str, Any]:
    """获取文件信息"""
    if not os.path.exists(file_path):
        return {}
    
    stat = os.stat(file_path)
    
    return {
        'size': stat.st_size,
        'created_at': datetime.fromtimestamp(stat.st_ctime),
        'modified_at': datetime.fromtimestamp(stat.st_mtime),
        'mime_type': mimetypes.guess_type(file_path)[0],
        'extension': os.path.splitext(file_path)[1].lower()
    }

def format_file_size(size_bytes: int) -> str:
    """格式化文件大小"""
    if size_bytes == 0:
        return "0 B"
    
    size_names = ["B", "KB", "MB", "GB", "TB"]
    i = 0
    
    while size_bytes >= 1024 and i < len(size_names) - 1:
        size_bytes /= 1024.0
        i += 1
    
    return f"{size_bytes:.1f} {size_names[i]}"

def validate_file_type(filename: str, allowed_types: List[str]) -> bool:
    """验证文件类型"""
    file_ext = os.path.splitext(filename)[1].lower().lstrip('.')
    return file_ext in allowed_types

def clean_filename(filename: str) -> str:
    """清理文件名，移除特殊字符"""
    # 保留文件扩展名
    name, ext = os.path.splitext(filename)
    
    # 清理文件名
    clean_name = slugify(name)
    
    return f"{clean_name}{ext}"

def ensure_directory_exists(directory_path: str) -> bool:
    """确保目录存在"""
    try:
        os.makedirs(directory_path, exist_ok=True)
        return True
    except Exception:
        return False

def get_upload_path(instance, filename: str) -> str:
    """生成上传路径"""
    # 根据模型类型确定子目录
    if hasattr(instance, 'source') and instance.source == 'template':
        subdir = 'templates'
    elif hasattr(instance, 'source') and instance.source == 'result':
        subdir = 'results'
    else:
        subdir = 'uploads'
    
    # 按日期分组
    date_path = datetime.now().strftime('%Y/%m/%d')
    
    # 生成唯一文件名
    unique_filename = generate_unique_filename(filename)
    
    return os.path.join(subdir, date_path, unique_filename)

def create_directory_structure():
    """创建必要的目录结构"""
    base_dirs = [
        'uploads',
        'templates', 
        'results',
        'temp',
        'logs'
    ]
    
    media_root = settings.MEDIA_ROOT
    
    for dir_name in base_dirs:
        dir_path = os.path.join(media_root, dir_name)
        ensure_directory_exists(dir_path)

def get_file_icon(filename: str) -> str:
    """根据文件扩展名获取图标类名"""
    file_ext = os.path.splitext(filename)[1].lower().lstrip('.')
    
    icon_mapping = {
        # 文档类型
        'pdf': 'fas fa-file-pdf text-danger',
        'doc': 'fas fa-file-word text-primary',
        'docx': 'fas fa-file-word text-primary',
        'txt': 'fas fa-file-alt text-secondary',
        
        # 表格类型
        'xls': 'fas fa-file-excel text-success',
        'xlsx': 'fas fa-file-excel text-success',
        'csv': 'fas fa-file-csv text-success',
        
        # 图片类型
        'jpg': 'fas fa-file-image text-info',
        'jpeg': 'fas fa-file-image text-info',
        'png': 'fas fa-file-image text-info',
        'gif': 'fas fa-file-image text-info',
        'bmp': 'fas fa-file-image text-info',
        'svg': 'fas fa-file-image text-info',
        
        # 压缩文件
        'zip': 'fas fa-file-archive text-warning',
        'rar': 'fas fa-file-archive text-warning',
        '7z': 'fas fa-file-archive text-warning',
        'tar': 'fas fa-file-archive text-warning',
        'gz': 'fas fa-file-archive text-warning',
        
        # 代码文件
        'py': 'fas fa-file-code text-info',
        'js': 'fas fa-file-code text-warning',
        'html': 'fas fa-file-code text-danger',
        'css': 'fas fa-file-code text-primary',
        'json': 'fas fa-file-code text-success',
        'xml': 'fas fa-file-code text-warning',
        
        # 音频文件
        'mp3': 'fas fa-file-audio text-purple',
        'wav': 'fas fa-file-audio text-purple',
        'flac': 'fas fa-file-audio text-purple',
        
        # 视频文件
        'mp4': 'fas fa-file-video text-dark',
        'avi': 'fas fa-file-video text-dark',
        'mov': 'fas fa-file-video text-dark',
        'wmv': 'fas fa-file-video text-dark',
    }
    
    return icon_mapping.get(file_ext, 'fas fa-file text-muted')

def parse_file_filters(filters: Dict[str, Any]) -> Dict[str, Any]:
    """解析文件过滤条件"""
    parsed_filters = {}
    
    # 文件类型过滤
    if 'file_type' in filters and filters['file_type']:
        parsed_filters['file_type__icontains'] = filters['file_type']
    
    # 文件大小过滤
    if 'min_size' in filters and filters['min_size']:
        try:
            parsed_filters['file_size__gte'] = int(filters['min_size'])
        except (ValueError, TypeError):
            pass
    
    if 'max_size' in filters and filters['max_size']:
        try:
            parsed_filters['file_size__lte'] = int(filters['max_size'])
        except (ValueError, TypeError):
            pass
    
    # 日期范围过滤
    if 'start_date' in filters and filters['start_date']:
        try:
            start_date = datetime.strptime(filters['start_date'], '%Y-%m-%d')
            parsed_filters['created_at__gte'] = start_date
        except (ValueError, TypeError):
            pass
    
    if 'end_date' in filters and filters['end_date']:
        try:
            end_date = datetime.strptime(filters['end_date'], '%Y-%m-%d')
            # 设置为当天结束时间
            end_date = end_date.replace(hour=23, minute=59, second=59)
            parsed_filters['created_at__lte'] = end_date
        except (ValueError, TypeError):
            pass
    
    # 文件名搜索
    if 'search' in filters and filters['search']:
        parsed_filters['original_name__icontains'] = filters['search']
    
    return parsed_filters

def get_task_status_display(status: str) -> Dict[str, str]:
    """获取任务状态显示信息"""
    status_mapping = {
        'pending': {
            'text': '等待中',
            'class': 'badge-secondary',
            'icon': 'fas fa-clock'
        },
        'processing': {
            'text': '处理中',
            'class': 'badge-primary',
            'icon': 'fas fa-spinner fa-spin'
        },
        'completed': {
            'text': '已完成',
            'class': 'badge-success',
            'icon': 'fas fa-check'
        },
        'failed': {
            'text': '失败',
            'class': 'badge-danger',
            'icon': 'fas fa-times'
        },
        'cancelled': {
            'text': '已取消',
            'class': 'badge-warning',
            'icon': 'fas fa-ban'
        }
    }
    
    return status_mapping.get(status, {
        'text': '未知',
        'class': 'badge-secondary',
        'icon': 'fas fa-question'
    })

def get_priority_display(priority: str) -> Dict[str, str]:
    """获取优先级显示信息"""
    priority_mapping = {
        'low': {
            'text': '低',
            'class': 'badge-light',
            'icon': 'fas fa-arrow-down'
        },
        'normal': {
            'text': '普通',
            'class': 'badge-info',
            'icon': 'fas fa-minus'
        },
        'high': {
            'text': '高',
            'class': 'badge-warning',
            'icon': 'fas fa-arrow-up'
        },
        'urgent': {
            'text': '紧急',
            'class': 'badge-danger',
            'icon': 'fas fa-exclamation'
        }
    }
    
    return priority_mapping.get(priority, {
        'text': '普通',
        'class': 'badge-info',
        'icon': 'fas fa-minus'
    })

def calculate_task_duration(started_at: Optional[datetime], completed_at: Optional[datetime]) -> str:
    """计算任务执行时长"""
    if not started_at:
        return '-'
    
    end_time = completed_at or datetime.now()
    duration = end_time - started_at
    
    total_seconds = int(duration.total_seconds())
    
    if total_seconds < 60:
        return f"{total_seconds}秒"
    elif total_seconds < 3600:
        minutes = total_seconds // 60
        seconds = total_seconds % 60
        return f"{minutes}分{seconds}秒"
    else:
        hours = total_seconds // 3600
        minutes = (total_seconds % 3600) // 60
        return f"{hours}小时{minutes}分"

def generate_task_log_entry(task_id: int, level: str, message: str, details: Optional[Dict] = None) -> Dict[str, Any]:
    """生成任务日志条目"""
    return {
        'timestamp': datetime.now().isoformat(),
        'task_id': task_id,
        'level': level,
        'message': message,
        'details': details or {}
    }

def sanitize_filename_for_download(filename: str) -> str:
    """为下载清理文件名"""
    # 移除或替换特殊字符
    import re
    
    # 保留文件扩展名
    name, ext = os.path.splitext(filename)
    
    # 移除特殊字符，保留中文、英文、数字、下划线、连字符
    clean_name = re.sub(r'[^\w\u4e00-\u9fff\-_\s]', '', name)
    
    # 替换空格为下划线
    clean_name = re.sub(r'\s+', '_', clean_name)
    
    # 限制长度
    clean_name = clean_name[:100]
    
    return f"{clean_name}{ext}"

def get_file_preview_url(file_instance) -> Optional[str]:
    """获取文件预览URL"""
    if not file_instance or not file_instance.file:
        return None
    
    # 检查文件是否支持预览
    file_ext = os.path.splitext(file_instance.original_name)[1].lower().lstrip('.')
    
    previewable_types = ['txt', 'csv', 'json', 'xml', 'html', 'md']
    
    if file_ext in previewable_types:
        return file_instance.file.url
    
    return None

def create_backup_filename(original_name: str) -> str:
    """创建备份文件名"""
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    name, ext = os.path.splitext(original_name)
    return f"{name}_backup_{timestamp}{ext}"

def validate_json_config(config_str: str) -> Dict[str, Any]:
    """验证JSON配置"""
    import json
    
    try:
        config = json.loads(config_str)
        return {
            'valid': True,
            'config': config,
            'error': None
        }
    except json.JSONDecodeError as e:
        return {
            'valid': False,
            'config': None,
            'error': str(e)
        }

def merge_configs(base_config: Dict, override_config: Dict) -> Dict:
    """合并配置字典"""
    merged = base_config.copy()
    
    for key, value in override_config.items():
        if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
            merged[key] = merge_configs(merged[key], value)
        else:
            merged[key] = value
    
    return merged